/** * Copyright (c) 2012-2016 André Bargull * Alle Rechte vorbehalten / All Rights Reserved. Use is subject to license terms. * * <https://github.com/anba/es6draft> */ package com.github.anba.es6draft.runtime.internal; import java.lang.reflect.Field; import java.nio.ByteBuffer; import java.nio.ReadOnlyBufferException; import java.security.AccessController; import java.security.PrivilegedActionException; import java.security.PrivilegedExceptionAction; import sun.misc.Unsafe; import sun.nio.ch.DirectBuffer; /** * */ @SuppressWarnings("restriction") final class UnsafeHolder { private UnsafeHolder() { } private static final Unsafe UNSAFE = initializeUnsafe(); private static final long BYTE_ARRAY_BASE_OFFSET = UNSAFE.arrayBaseOffset(byte[].class); private static Unsafe initializeUnsafe() { try { return Unsafe.getUnsafe(); } catch (SecurityException e) { try { return AccessController.doPrivileged((PrivilegedExceptionAction<Unsafe>) () -> { Field f = Unsafe.class.getDeclaredField("theUnsafe"); f.setAccessible(true); return (Unsafe) f.get(null); }); } catch (PrivilegedActionException e2) { throw new ExceptionInInitializerError(e2.getException()); } } } private static Object baseObject(ByteBuffer buffer) { if (buffer.hasArray()) { return buffer.array(); } return null; } private static long offsetOrMemoryAddress(ByteBuffer buffer, int index, int size) { if (index < 0 || size > buffer.limit() - index) { throw new IndexOutOfBoundsException(indexOutOfBoundsMessage(buffer, index, size)); } if (buffer.isReadOnly()) { throw new ReadOnlyBufferException(); } if (buffer.hasArray()) { return BYTE_ARRAY_BASE_OFFSET + buffer.arrayOffset() + index; } assert buffer.isDirect(); return ((DirectBuffer) buffer).address() + index; } private static String indexOutOfBoundsMessage(ByteBuffer buffer, int index, int size) { return String.format("limit=%d, index=%d, size=%d", buffer.limit(), index, size); } /** * Calls {@link Unsafe#getIntVolatile(Object, long)}. * * @param buffer * the byte buffer * @param index * the byte buffer index * @return the value */ static int getIntVolatile(ByteBuffer buffer, int index) { Object base = baseObject(buffer); long offset = offsetOrMemoryAddress(buffer, index, Integer.BYTES); return UNSAFE.getIntVolatile(base, offset); } }